package client

import (
	. "Go-Easy/pkg/config"
	. "Go-Easy/pkg/microservice/credentials"
	"fmt"
	clientv3 "go.etcd.io/etcd/client/v3"
	"go.etcd.io/etcd/client/v3/naming/resolver"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

type easyClient struct {
	ServiceName  string
	dial_options []grpc.DialOption
	cfg          Config_Client
	clientPool   *ConnectPool
}

func NewEasyClient(ServiceName string, DialOption ...grpc.DialOption) *easyClient {
	return &easyClient{
		ServiceName:  ServiceName,
		dial_options: DialOption,
		cfg:          ClientMap[ServiceName],
	}
}

//根据配置文件生成新的connect
func (e *easyClient) CreateNewClientConnect() (*grpc.ClientConn, error) {
	//如果实例中已经有连接池，则直接获取
	if e.clientPool != nil {
		//log.Println("直接获取，不再重新解析")
		return e.clientPool.Get(), nil
	}

	var options []grpc.DialOption
	var target string

	//是否从ETCD中解析获得服务地址
	if e.cfg.ServiceDiscovery {
		//使用etcd做服务发现连接
		cli, err := clientv3.NewFromURL(ETCD.URL)
		if err != nil {
			return nil, err
		}
		etcdResolver, _ := resolver.NewBuilder(cli)
		target = fmt.Sprintf("etcd:///%s", e.ServiceName)
		options = append(options, grpc.WithResolvers(etcdResolver))
	} else {
		target = e.cfg.Address
	}

	//如果配置文件中有证书路径，则使用TLS加密，否则不加密
	if e.cfg.UseTLS {
		if cred, err := GenerateTLSCredentials(); err == nil {
			options = append(options, grpc.WithTransportCredentials(cred))
		} else {
			return nil, err
		}
	} else {
		options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
	}

	//添加用户传入的DialOption
	options = append(options, e.dial_options...)

	//如果配置文件中指定使用连接池
	if e.cfg.UsePool {
		//log.Println("创建连接池")
		e.clientPool = CreatePool(target, options...)
		return e.clientPool.Get(), nil
	}

	conn, err := grpc.Dial(target, options...)
	return conn, err
}

//若使用连接池,则将conn put入池；反之则直接close
func (e *easyClient) ConnectClose(conn *grpc.ClientConn) {
	//log.Print("调用ConnectClose")
	//如果实例中已经有连接池，则将conn放回连接池
	if e.clientPool != nil {
		e.clientPool.Put(conn)
		return
	}

	conn.Close()
}
